package roleMenuController

import (
	"CMETO/models"
	"CMETO/utils"
	"CMETO/utils/jwt"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type RoleMenuController struct{}

// @Summary 查询该角色下的所有权限列表
// @Description 查询该角色权限列表
// @Tags 角色权限管理
// @Produce json
// @Success 200 {object} models.ResultCommon[[]models.Menu] "查询成功"
// @Fail 401 {object} models.ErrorResult "查询成功"
// @Router /menurole/role [get]
// @Security JWT
func (rm RoleMenuController) QueryRoleMenus(ctx *gin.Context) {
	// 从token中获取角色id
	token, _ := ctx.Get("token")
	user := token.(*jwt.MyClaims).User
	var role_id int
	if len(user.Roles) == 0 {
		role_id = 5
	} else {
		role_id = token.(*jwt.MyClaims).User.Roles[0].RoleId
	}
	if role_id == 0 {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "该角色未授权",
			Code:   "400",
			Result: nil,
		})
		return
	}
	// 设置承载体
	menuList := []models.Menu{}
	// 查询
	models.DB.
		Joins("JOIN role_menu ON menus.id = role_menu.menu_id").
		Where("role_menu.role_id = ? AND is_delete = 0", role_id).
		Find(&menuList)

	ctx.JSON(http.StatusOK, &models.ResultCommon[[]models.Menu]{
		Msg:    "ok",
		Code:   "200",
		Result: menuList,
	})
}

// @Summary 查询该角色下的所有权限（树状）
// @Description 查询该角色权限列表(树状)
// @Tags 角色权限管理
// @Produce json
// @Success 200 {object} models.ResultCommon[[]models.Menu] "查询成功"
// @Fail 401 {object} models.ErrorResult "查询成功"
// @Router /menurole/tree [get]
// @Security JWT
func (rm RoleMenuController) QueryRoleMenuTrees(ctx *gin.Context) {
	// 从token中获取角色id
	token, _ := ctx.Get("token")
	user := token.(*jwt.MyClaims).User
	var role_id int
	if len(user.Roles) == 0 {
		role_id = 5
	} else {
		role_id = token.(*jwt.MyClaims).User.Roles[0].RoleId
	}
	if role_id == 0 {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "该角色未授权",
			Code:   "400",
			Result: nil,
		})
		return
	}
	result, _ := GetMenuTree(role_id, false)

	ctx.JSON(http.StatusOK, &models.ResultCommon[[]models.Menu]{
		Msg:    "ok",
		Code:   "200",
		Result: result,
	})
}

// @Summary 根据角色Id查询权限
// @Description 根据角色Id查询权限
// @Tags 角色权限管理
// @Produce json
// @Param id path string true "角色id"
// @Success 200 {object} models.ResultCommon[[]models.Menu] "查询成功"
// @Fail 401 {object} models.ErrorResult "查询成功"
// @Router /rolemenu/{id} [get]
// @Security JWT
func (rm RoleMenuController) QueryRoleMenuTreesById(ctx *gin.Context) {
	role_id, _ := strconv.Atoi(ctx.Param("id"))
	if role_id == 0 {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "该角色未授权",
			Code:   "400",
			Result: nil,
		})
		return
	}
	// 设置承载体
	menuList := []models.Menu{}
	// 查询
	models.DB.
		Joins("JOIN role_menu ON menus.id = role_menu.menu_id").
		Where("role_menu.role_id = ? AND menus.is_delete = 0", role_id).
		Find(&menuList)

	ctx.JSON(http.StatusOK, &models.ResultCommon[[]models.Menu]{
		Msg:    "ok",
		Code:   "200",
		Result: menuList,
	})
}

// @Summary 查询该角色下的所有权限（树状没有按钮）
// @Description 查询该角色权限列表(树状没有按钮)
// @Tags 角色权限管理
// @Produce json
// @Success 200 {object} models.ResultCommon[[]models.Menu] "查询成功"
// @Fail 401 {object} models.ErrorResult "查询成功"
// @Router /menurole/tree/nobtn [get]
// @Security JWT
func (rm RoleMenuController) QueryRoleMenuTreesNoBtn(ctx *gin.Context) {
	// 从token中获取角色id
	token, _ := ctx.Get("token")
	user := token.(*jwt.MyClaims).User
	var role_id int
	if len(user.Roles) == 0 {
		role_id = 5
	} else {
		role_id = token.(*jwt.MyClaims).User.Roles[0].RoleId
	}
	if role_id == 0 {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "该角色未授权",
			Code:   "400",
			Result: nil,
		})
		return
	}
	result, _ := GetMenuTree(role_id, true)

	ctx.JSON(http.StatusOK, &models.ResultCommon[[]models.Menu]{
		Msg:    "ok",
		Code:   "200",
		Result: result,
	})
}

// @Summary 查询该角色下的所有权限（只获取按钮）
// @Description 查询该角色权限列表(只获取按钮)
// @Tags 角色权限管理
// @Produce json
// @Success 200 {object} models.ResultCommon[[]models.Menu] "查询成功"
// @Fail 401 {object} models.ErrorResult "查询成功"
// @Router /menurole/btn [get]
// @Security JWT
func (rm RoleMenuController) QueryRoleBtn(ctx *gin.Context) {
	// 从token中获取角色id
	token, _ := ctx.Get("token")
	user := token.(*jwt.MyClaims).User
	var role_id int
	if len(user.Roles) == 0 {
		role_id = 0
	} else {
		role_id = token.(*jwt.MyClaims).User.Roles[0].RoleId
	}
	if role_id == 0 {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "该角色未授权",
			Code:   "400",
			Result: nil,
		})
		return
	}
	menuList := []models.Menu{}
	// 查
	models.DB.
		Joins("JOIN role_menu ON menus.id = role_menu.menu_id").
		Where("role_menu.role_id = ? AND menus.type=3 AND menus.is_delete = 0", role_id).
		Find(&menuList)

	ctx.JSON(http.StatusOK, &models.ResultCommon[[]models.Menu]{
		Msg:    "ok",
		Code:   "200",
		Result: menuList,
	})
}

// 获得树的根部
func GetMenuTree(id int, btn bool) ([]models.Menu, error) {
	menuList := []models.Menu{}
	// 查
	models.DB.
		Preload("Role", "is_delete=0").
		Joins("JOIN role_menu ON menus.id = role_menu.menu_id").
		Where("role_menu.role_id = ? AND menus.is_delete = 0", id).
		Find(&menuList)
	var result []models.Menu
	for _, menu := range menuList {
		if menu.Fid == 0 {
			result = append(result, menu)
			if btn {
				buildTree(&result[len(result)-1], menuList, 3)
			} else {
				buildTree(&result[len(result)-1], menuList, 4)
			}
		}
	}
	return result, nil
}

// 递归方法，把层级嵌套起来
func buildTree(parent *models.Menu, menus []models.Menu, btn models.Type) {
	for _, menu := range menus {
		if menu.Fid == parent.Id && menu.Type != btn {
			parent.Children = append(parent.Children, menu)
			buildTree(&parent.Children[len(parent.Children)-1], menus, btn)
		}
	}
}

// @Summary 新增权限
// @Description 传入json，新增权限
// @Tags 角色权限管理
// @Accept json
// @Produce json
// @Param menuInfo body models.MenuAddParams true "权限信息"
// @Success 200 {object} models.AddResult "新增成功"
// @fail 400 {object} models.ErrorResult "数据错误"
// @fail 401 {object} models.AddResult "新增失败"
// @Router /menurole [post]
// @Security JWT
func (rm RoleMenuController) AddMenuWithRole(ctx *gin.Context) {
	menu := &models.MenuAddParams{}
	// 绑定json数据
	if err := ctx.ShouldBindJSON(&menu); err != nil {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "参数异常",
			Code:   "400",
			Result: err,
		})
	} else {
		menu.CreateTime = utils.TimeFormatter(time.Now())
		menu.UpdateTime = utils.TimeFormatter(time.Now())
		// 从token中获取用户id
		token, _ := ctx.Get("token")
		id := token.(*jwt.MyClaims).User.Id
		menu.CreateUserId = id
		menu.UpdateUserId = id
		menuTemp := menu.Menu
		// 开启事务
		result := models.DB.Transaction(func(tx *gorm.DB) error {
			if r1 := tx.Model(&models.Menu{}).Create(&menuTemp).Error; r1 != nil {
				return r1
			}
			for i := 0; i < len(menu.RoleId); i++ {
				if r2 := tx.Model(&models.RoleMenu{}).Create(&models.RoleMenu{
					RoleId: menu.RoleId[i],
					MenuId: menuTemp.Id,
				}).Error; r2 != nil {
					return r2
				}
			}
			return nil
		})
		if result != nil {
			ctx.JSON(http.StatusOK, &models.AddResult{
				Msg:    "新增失败",
				Code:   "400",
				Result: 0,
			})
		} else {
			ctx.JSON(http.StatusOK, &models.AddResult{
				Msg:    "新增成功",
				Code:   "200",
				Result: 1,
			})
		}
	}
}

// @Summary 更新权限
// @Description 传入json，更新权限
// @Tags 角色权限管理
// @Accept json
// @Produce json
// @Param MenuInfo body models.MenuAddParams true "权限信息"
// @Success 200 {object} models.UpdateResult[models.Menu] "更新成功"
// @fail 400 {object} models.ErrorResult "数据错误"
// @fail 401 {object} models.ErrorResult "更新失败"
// @Router /menurole [put]
// @Security JWT
func (rm RoleMenuController) UpdateMenuWithRole(ctx *gin.Context) {
	// 定义接收数据的承载体
	var menu models.MenuAddParams
	// 绑定json数据
	if err := ctx.ShouldBindJSON(&menu); err != nil {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "参数异常",
			Code:   "400",
			Result: err,
		})
		return
	}
	// 从token中获取用户id
	token, _ := ctx.Get("token")
	id := token.(*jwt.MyClaims).User.Id
	menu.UpdateUserId = id
	menu.UpdateTime = utils.TimeFormatter(time.Now())
	result := models.DB.Transaction(func(tx *gorm.DB) error {
		// 更新权限表
		if r1 := tx.Model(&models.Menu{}).Where("id=?", menu.Id).Save(&menu.Menu).Error; r1 != nil {
			return r1
		}
		// 删掉组合
		role_menu := &models.RoleMenu{}
		tx.Where("menu_id = ?", menu.Id).Delete(&role_menu)
		// 新增组合
		for i := 0; i < len(menu.RoleId); i++ {
			if r2 := tx.Model(&models.RoleMenu{}).Create(&models.RoleMenu{
				RoleId: menu.RoleId[i],
				MenuId: menu.Id,
			}).Error; r2 != nil {
				return r2
			}
		}
		return nil
	})
	if result != nil {
		ctx.JSON(http.StatusOK, models.ErrorResult{
			Msg:    "更新失败",
			Code:   "400",
			Result: nil,
		})
	} else {
		ctx.JSON(http.StatusOK, models.UpdateResult[models.Menu]{
			Msg:    "更新成功",
			Code:   "200",
			Result: menu.Menu,
		})
	}
}

// @Summary 新增角色
// @Description 传入json，新增角色
// @Tags 角色权限管理
// @Accept json
// @Produce json
// @Param roleInfo body models.RoleAddParams true "角色信息"
// @Success 200 {object} models.AddResult "新增成功"
// @fail 400 {object} models.ErrorResult "数据错误"
// @fail 401 {object} models.AddResult "新增失败"
// @Router /rolemenu [post]
// @Security JWT
func (rm RoleMenuController) AddRoleWithMenu(ctx *gin.Context) {
	role := &models.RoleAddParams{}
	// 绑定json数据
	if err := ctx.ShouldBindJSON(&role); err != nil {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "参数异常",
			Code:   "400",
			Result: err,
		})
		return
	}
	role.CreateTime = utils.TimeFormatter(time.Now())
	roleTemp := role.Role
	// 开启事务
	result := models.DB.Transaction(func(tx *gorm.DB) error {
		if r1 := tx.Model(&models.Role{}).Create(&roleTemp).Error; r1 != nil {
			return r1
		}
		// 创建角色-菜单映射表
		for i := 0; i < len(role.MenuId); i++ {
			if r2 := tx.Model(&models.RoleMenu{}).Create(&models.RoleMenu{
				RoleId: roleTemp.Id,
				MenuId: role.MenuId[i],
			}).Error; r2 != nil {
				return r2
			}
		}
		return nil
	})
	if result != nil {
		ctx.JSON(http.StatusOK, &models.AddResult{
			Msg:    "新增失败",
			Code:   "400",
			Result: 0,
		})
	} else {
		ctx.JSON(http.StatusOK, &models.AddResult{
			Msg:    "新增成功",
			Code:   "200",
			Result: 1,
		})
	}
}

// @Summary 更新角色
// @Description 传入json，更新角色
// @Tags 角色权限管理
// @Accept json
// @Produce json
// @Param RoleInfo body models.RoleAddParams true "角色信息"
// @Success 200 {object} models.UpdateResult[models.Role] "更新成功"
// @fail 400 {object} models.ErrorResult "数据错误"
// @fail 401 {object} models.ErrorResult "更新失败"
// @Router /rolemenu [put]
// @Security JWT
func (rm RoleMenuController) UpdateRoleWithMenu(ctx *gin.Context) {
	// 定义接收数据的承载体
	var role models.RoleAddParams
	// 绑定json数据
	if err := ctx.ShouldBindJSON(&role); err != nil {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "参数异常",
			Code:   "400",
			Result: err,
		})
		return
	}
	// 绑定角色信息
	role_old := &models.Role{}
	// 查找角色信息
	models.DB.First(&role_old, role.Id)
	if role_old.Id == 0 {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "角色不存在",
			Code:   "400",
			Result: nil,
		})
	}
	roleTemp := role.Role
	result := models.DB.Transaction(func(tx *gorm.DB) error {
		if r1 := tx.Model(&roleTemp).Save(&role.Role).Error; r1 != nil {
			return r1
		}
		role_menu := &models.RoleMenu{}
		tx.Where("role_id = ?", role.Id).Delete(&role_menu)
		for i := 0; i < len(role.MenuId); i++ {
			if r2 := tx.Model(&models.RoleMenu{}).Create(&models.RoleMenu{
				RoleId: role.Id,
				MenuId: role.MenuId[i],
			}).Error; r2 != nil {
				return r2
			}
		}
		return nil
	})
	if result != nil {
		ctx.JSON(http.StatusOK, &models.ErrorResult{
			Msg:    "更新失败",
			Code:   "400",
			Result: result,
		})
	} else {
		ctx.JSON(http.StatusOK, &models.UpdateResult[models.Role]{
			Msg:    "更新成功",
			Code:   "200",
			Result: roleTemp,
		})
	}
}
